unit gm_engine;

interface

uses
  zglHeader, Scenes;

// MOUSE
const
  M_BLEFT   = 0;
  M_BMIDDLE = 1;
  M_BRIGHT  = 2;
  M_WUP     = 0;
  M_WDOWN   = 1;
  
const
// KEYBOARD
  K_SYSRQ      = $B7;
  K_PAUSE      = $C5;
  K_ESCAPE     = $01;
  K_ENTER      = $1C;
  K_KP_ENTER   = $9C;

  K_UP         = $C8;
  K_DOWN       = $D0;
  K_LEFT       = $CB;
  K_RIGHT      = $CD;

  K_BACKSPACE  = $0E;
  K_SPACE      = $39;
  K_TAB        = $0F;
  K_TILDE      = $29;

  K_INSERT     = $D2;
  K_DELETE     = $D3;
  K_HOME       = $C7;
  K_END        = $CF;
  K_PAGEUP     = $C9;
  K_PAGEDOWN   = $D1;

  K_CTRL       = $FF - $01;
  K_CTRL_L     = $1D;
  K_CTRL_R     = $9D;
  K_ALT        = $FF - $02;
  K_ALT_L      = $38;
  K_ALT_R      = $B8;
  K_SHIFT      = $FF - $03;
  K_SHIFT_L    = $2A;
  K_SHIFT_R    = $36;
  K_SUPER      = $FF - $04;
  K_SUPER_L    = $DB;
  K_SUPER_R    = $DC;
  K_APP_MENU   = $DD;

  K_CAPSLOCK   = $3A;
  K_NUMLOCK    = $45;
  K_SCROLL     = $46;

  K_BRACKET_L  = $1A; // [ {
  K_BRACKET_R  = $1B; // ] }
  K_BACKSLASH  = $2B; // \
  K_SLASH      = $35; // /
  K_COMMA      = $33; // ,
  K_DECIMAL    = $34; // .
  K_SEMICOLON  = $27; // : ;
  K_APOSTROPHE = $28; // ' "

  K_0          = $0B;
  K_1          = $02;
  K_2          = $03;
  K_3          = $04;
  K_4          = $05;
  K_5          = $06;
  K_6          = $07;
  K_7          = $08;
  K_8          = $09;
  K_9          = $0A;

  K_MINUS      = $0C;
  K_EQUALS     = $0D;

  K_A          = $1E;
  K_B          = $30;
  K_C          = $2E;
  K_D          = $20;
  K_E          = $12;
  K_F          = $21;
  K_G          = $22;
  K_H          = $23;
  K_I          = $17;
  K_J          = $24;
  K_K          = $25;
  K_L          = $26;
  K_M          = $32;
  K_N          = $31;
  K_O          = $18;
  K_P          = $19;
  K_Q          = $10;
  K_R          = $13;
  K_S          = $1F;
  K_T          = $14;
  K_U          = $16;
  K_V          = $2F;
  K_W          = $11;
  K_X          = $2D;
  K_Y          = $15;
  K_Z          = $2C;

  K_KP_0       = $52;
  K_KP_1       = $4F;
  K_KP_2       = $50;
  K_KP_3       = $51;
  K_KP_4       = $4B;
  K_KP_5       = $4C;
  K_KP_6       = $4D;
  K_KP_7       = $47;
  K_KP_8       = $48;
  K_KP_9       = $49;

  K_KP_SUB     = $4A;
  K_KP_ADD     = $4E;
  K_KP_MUL     = $37;
  K_KP_DIV     = $B5;
  K_KP_DECIMAL = $53;

  K_F1         = $3B;
  K_F2         = $3C;
  K_F3         = $3D;
  K_F4         = $3E;
  K_F5         = $3F;
  K_F6         = $40;
  K_F7         = $41;
  K_F8         = $42;
  K_F9         = $43;
  K_F10        = $44;
  K_F11        = $57;
  K_F12        = $58;

  KA_DOWN     = 0;
  KA_UP       = 1;

const
  K_INV       = K_I;
  K_CHAR      = K_C;
  K_SKILL     = K_A;

const
  FOM_CREATE  = $01; // Create
  FOM_OPENR   = $02; // Read

  PR2D_FILL   = $010000;
  PR2D_SMOOTH = $020000;

const
  TEXT_HALIGN_LEFT    = $000001;
  TEXT_HALIGN_CENTER  = $000002;
  TEXT_HALIGN_RIGHT   = $000004;
  TEXT_HALIGN_JUSTIFY = $000008;
  TEXT_VALIGN_TOP     = $000010;
  TEXT_VALIGN_CENTER  = $000020;
  TEXT_VALIGN_BOTTOM  = $000040;
  TEXT_CLIP_RECT      = $000080;
  TEXT_FX_VCA         = $000100;
  TEXT_FX_LENGTH      = $000200;

// FX
const
  FX_BLEND_NORMAL = $00;
  FX_BLEND_ADD    = $01;
  FX_BLEND_MULT   = $02;
  FX_BLEND_BLACK  = $03;
  FX_BLEND_WHITE  = $04;
  FX_BLEND_MASK   = $05;

  FX_COLOR_MIX    = $00;
  FX_COLOR_SET    = $01;

  FX_BLEND        = $100000;
  FX_COLOR        = $200000;

// FX 2D
const
  FX2D_FLIPX    = $000001;
  FX2D_FLIPY    = $000002;
  FX2D_VCA      = $000004;
  FX2D_VCHANGE  = $000008;
  FX2D_SCALE    = $000010;
  FX2D_RPIVOT   = $000020;

type
  TPoint = record
    X, Y : Integer;
  end;

type
  TRect = record
    Left, Top, Width, Height: Integer;
  end;

type
  TCamera2D = zglTCamera2D;
  TPCamera2D = zglPCamera2D;

type
  TFont = zglPFont;
  TFile = zglTFile;
  TTexture = zglPTexture;

const
  SlotSize   = 34;

var
  ScreenWidth      : Integer = 800;// + 500;
  ScreenHeight     : Integer = 600;// + 0;// + 300;

  FullScr          : Boolean = False;
  VSync            : Boolean = False;

  ChBIFlag         : Boolean = False;
  
  Cam              : TCamera2D;
  MPrev            : TPoint;

  NMTime           : Integer;
  NewGame          : Boolean = False;

  ShowMinimap      : Boolean = True;

  SpellPoints      : Integer = 0;
  SellSpellN       : Integer = -1;
  BtnDwn           : Integer;

  WalkPause        : Integer;

  MapSide          : Integer = 50;

procedure SetCam;
function Rect(X, Y, Width, Height: Integer): TRect;
function PointInRect(P: TPoint; X, Y, Width, Height: Integer): Boolean;
function MouseInRect(X, Y, Width, Height: Integer): Boolean;
function StrToPAChar(const Value: string): PAnsiChar;
//function A2U8(const S: string; const cp: integer = 1251): UTF8String;
function Angle(x1, y1, x2, y2 : Single): Single;
function Sin(Angle : Integer): Single;
function Cos(Angle : Integer): Single;
function GetFileExt(const FileName: string): UTF8String;
function GetDirectory(const FileName: string): UTF8String;
function GetFileName(const FileName: string): UTF8String;
function IntToStr(Value: Integer): UTF8String;
procedure SetFrameSize(var Texture: zglPTexture; FrameWidth, FrameHeight: Word);
function LoadTexture(const FileName: string; TransparentColor: LongWord = TEX_NO_COLORKEY; Flags: LongWord = TEX_DEFAULT_2D): TTexture;
function LoadFont(const FileName: string): TFont;
function GetDist(A, B: TPoint): Single;
function MouseDown(Button: Byte): Boolean;
function MouseUp(Button: Byte): Boolean;
function MouseClick(Button: Byte): Boolean;
function MouseDblClick(Button: Byte): Boolean;
function MouseWheel(Axis: Byte): Boolean;
function SetScreenOptions(Width, Height, Refresh: Word; FullScreen, VSync: Boolean): Boolean;
function KeyDown(KeyCode: Byte): Boolean;
function KeyPress(KeyCode: Byte): Boolean;
procedure ClearStates;
procedure ClearKeyState;
procedure ClearMouseState;
procedure TextOut(Font: TFont; X, Y : Single; const Text: string; Flags: LongWord = 0); overload;
procedure TextOut(Font: TFont; X, Y, Scale, Step: Single; const Text: string; Alpha: Byte = 255; Color: LongWord = $FFFFFF; Flags: LongWord = 0); overload;
function TextWidth(Font: TFont; const Text: string; Step: Single = 0.0): Single;
procedure InitCamera2D(out Camera: TCamera2D);
procedure SetCamera2D(Camera: TPCamera2D);
function FileGetSize(FileHandle: TFile): LongWord;
function FileWrite(FileHandle: TFile; const Buffer; Bytes: LongWord): LongWord;
function FileOpen(out FileHandle: TFile; const FileName: UTF8String; Mode: Byte): Boolean;
function FileRead(FileHandle: TFile; var Buffer; Bytes: LongWord): LongWord;
procedure FileClose(var FileHandle: TFile);  
function StrToBool(const S: string): Boolean;
function UpperCase(const S: string): UTF8String;
procedure Circ2D(X, Y, Radius: Single; Color: LongWord = $FFFFFF; Alpha: Byte = 255; Quality: Word = 32; FX: LongWord = 0);
procedure Rect2D(X, Y, W, H: Single; Color: LongWord = $FFFFFF; Alpha: Byte = 255; FX: LongWord = 0);
procedure Render2D(Texture: zglPTexture; X, Y, W, H, Angle: Single; Frame: Word; Alpha: Byte = 255; FX: LongWord = FX_BLEND);
procedure RenderSprite2D(Texture: zglPTexture; X, Y, W, H, Angle: Single; Alpha: Byte = 255; FX: LongWord = FX_BLEND);  
function Point(X, Y: Integer): TPoint;
function GetMouse: TPoint;

implementation

uses Windows, gm_creature;

function Rect(X, Y, Width, Height: Integer): TRect;
begin
  Result.Left := X;
  Result.Top := Y;
  Result.Width := Width;
  Result.Height := Height;
end;

procedure SetCam;
begin
  Cam.X := PC.Pos.X * 32 - ScreenWidth div 2 + 16;
  Cam.Y := PC.Pos.Y * 32 - ScreenHeight div 2 + 16;
end;

function MouseInRect(X, Y, Width, Height: Integer): Boolean;
begin
  Result := (GetMouse.X > X) and (GetMouse.Y > Y) and (GetMouse.X < X + Width) and (GetMouse.Y < Y + Height);
end;

function PointInRect(P: TPoint; X, Y, Width, Height: Integer): Boolean;
begin
  Result := (P.X > X) and (P.Y > Y) and (P.X < X + Width) and (P.Y < Y + Height);
end;

function StrToPAChar(const Value: string): PAnsiChar;
begin
  Result := PAnsiChar(AnsiString(Value));
end;

function A2U8(const S: string; const cp: integer = 1251): UTF8String;
var
  wlen, ulen: Integer;
  wbuf: PWideChar;
begin
  Result := '';
  wlen := MultiByteToWideChar(cp, 0, StrToPAChar(S), length(S), NIL, 0); // wlen is the number of UCS2 without NULL terminater.
  if wlen = 0 then exit;
  wbuf := GetMemory(wlen * sizeof(wchar));
  try
    MultiByteToWideChar(cp, 0, StrToPAChar(S), length(S), wbuf, wlen);
    ulen := WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NIL, 0, NIL, NIL);
    setlength(Result, ulen);
    WideCharToMultiByte(CP_UTF8, 0, wbuf, wLen, StrToPAChar(Result), uLen, NIL, NIL);
  finally
    FreeMemory(WBuf);
  end;
end;

function Cos(Angle: Integer): Single;
begin
  Result := m_Cos(Angle)
//  Result := System.Cos(Angle)
end;

function Sin(Angle: Integer): Single;
begin
  Result := m_Sin(Angle)
//  Result := System.Sin(Angle)
end;

function Angle(x1, y1, x2, y2: Single): Single;
begin                                             
  Result := m_Angle(x1, y1, x2, y2)
end;

function GetFileExt(const FileName: string): UTF8String;
begin
  Result := file_GetExtension(A2U8(FileName))
end;

function GetDirectory(const FileName: string): UTF8String;
begin
  Result := file_GetDirectory(A2U8(FileName))
end;

function GetFileName(const FileName: string): UTF8String;
begin
  Result := file_GetName(A2U8(FileName))
end;

function IntToStr(Value: Integer): UTF8String;
begin
  Result := u_IntToStr(Value)
end;

procedure SetFrameSize(var Texture: zglPTexture; FrameWidth, FrameHeight: Word);
begin
  tex_SetFrameSize(Texture, FrameWidth, FrameHeight)
end;

function LoadTexture(const FileName: string; TransparentColor: LongWord = TEX_NO_COLORKEY; Flags: LongWord = TEX_DEFAULT_2D): TTexture;
begin
  Result := tex_LoadFromFile(A2U8(FileName), TransparentColor, Flags)
end;

function LoadFont(const FileName: string): TFont;
begin
  Result := font_LoadFromFile(A2U8(FileName))
end;

function GetDist(A, B: TPoint): Single;
begin
//  Result := m_Distance(x1, y1, x2, y2)
  Result := sqrt(sqr(B.X - A.X) + sqr(B.Y - A.Y));
end;

function MouseDown(Button: Byte): Boolean;
begin
  Result := mouse_Down(Button)
end;

function MouseUp(Button: Byte): Boolean;
begin
  Result := mouse_Up(Button)
end;

function MouseClick(Button: Byte): Boolean;
begin
  Result := mouse_Click(Button)
end;

function MouseDblClick(Button: Byte): Boolean;
begin
  Result := mouse_DblClick(Button)
end;

function MouseWheel(Axis: Byte): Boolean;
begin
  Result := mouse_Wheel(Axis)
end;

function SetScreenOptions(Width, Height, Refresh: Word; FullScreen, VSync: Boolean): Boolean;
begin
  Result := scr_SetOptions(Width, Height, Refresh, FullScreen, VSync);
end;

function KeyDown(KeyCode: Byte): Boolean;
begin
  Result := key_Down(KeyCode)
end;

function KeyPress(KeyCode: Byte): Boolean;
begin
  Result := key_Press(KeyCode)
end;

procedure ClearMouseState;
begin
  mouse_ClearState
end;

procedure ClearKeyState;
begin
  key_ClearState
end;

procedure ClearStates;
begin
  mouse_ClearState;
  key_ClearState;
end;

procedure TextOut(Font: TFont; X, Y : Single; const Text: string; Flags: LongWord = 0); overload;
begin
  text_Draw(Font, X, Y, A2U8(Text), Flags)
end;

procedure TextOut(Font: TFont; X, Y, Scale, Step: Single; const Text: string; Alpha: Byte = 255; Color: LongWord = $FFFFFF; Flags: LongWord = 0); overload;
begin
  text_DrawEx(Font, X, Y, Scale, Step, A2U8(Text), Alpha, Color, Flags)
end;

function TextWidth(Font: TFont; const Text: string; Step: Single = 0.0): Single;
begin
  Result := text_GetWidth(Font, A2U8(Text), Step)
end;

procedure InitCamera2D(out Camera: TCamera2D);
begin
  cam2d_Init(Camera)
end;

procedure SetCamera2D(Camera: TPCamera2D);
begin
  cam2d_Set(Camera)
end;

function FileGetSize(FileHandle: TFile): LongWord;
begin
  Result := file_GetSize(FileHandle)
end;

function FileWrite(FileHandle: TFile; const Buffer; Bytes: LongWord): LongWord;
begin
  Result := file_Write(FileHandle, Buffer, Bytes)
end;

function FileOpen(out FileHandle: TFile; const FileName: UTF8String; Mode: Byte): Boolean;
begin
  Result := file_Open(FileHandle, FileName, Mode)
end;

function FileRead(FileHandle: TFile; var Buffer; Bytes: LongWord): LongWord;
begin
  Result := file_Read(FileHandle, Buffer, Bytes)
end;

procedure FileClose(var FileHandle: TFile);
begin
  file_Close(FileHandle)
end;

function StrToBool(const S: string): Boolean;
begin
  Result := u_StrToBool(A2U8(S))
end;

function UpperCase(const S: string): UTF8String;
begin
  Result := u_StrUp(A2U8(S))
end;

procedure Rect2D(X, Y, W, H: Single; Color: LongWord = $FFFFFF; Alpha: Byte = 255; FX: LongWord = 0);
begin
  pr2d_Rect(X, Y, W, H, Color, Alpha, FX)
end;

procedure Circ2D(X, Y, Radius: Single; Color: LongWord = $FFFFFF; Alpha: Byte = 255; Quality: Word = 32; FX: LongWord = 0);
begin
  pr2d_Circle(X, Y, Radius, Color, Alpha, Quality, FX);
end;

procedure Render2D(Texture: zglPTexture; X, Y, W, H, Angle: Single; Frame: Word; Alpha: Byte = 255; FX: LongWord = FX_BLEND);
begin
  asprite2d_Draw(Texture, X, Y, W, H, Angle, Frame, Alpha, FX)
end;

procedure RenderSprite2D(Texture: zglPTexture; X, Y, W, H, Angle: Single; Alpha: Byte = 255; FX: LongWord = FX_BLEND);
begin
  ssprite2d_Draw(Texture, X, Y, W, H, Angle, Alpha, FX);
end;

function Point(X, Y: Integer): TPoint;
begin
  Result.X := X;
  Result.Y := Y;  
end;

function GetMouse: TPoint;
begin
  Result := Point(mouse_X, mouse_Y);
end;

end.
